package com.nwpu.main;

import com.nwpu.pojo.Meeting;
import com.nwpu.pojo.User;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * MethodSetImpl
 *
 * @author 龙虹宇
 * @version 1.0
 * @date 2023/11/11
 */
public class MethodSetImpl extends UnicastRemoteObject implements MethodSet {
    // 静态用户集合
    private static Hashtable<Integer, User> userHashtable = new Hashtable<>();
    private static Collection<User> users;
    // 静态会议集合
    private static Hashtable<Integer, Meeting> meetingHashtable = new Hashtable<>();
    private static Collection<Meeting> meetings;
    // Date格式定义
    private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

    // 指令集
    private static final String[] INSTRUCTIONS = {
            "register", "add"
            , "query", "delete", "clear"
            , "help", "quit"
    };
    // 指令集描述
    private static final String[] INSTRUCTIONS_DES = {
            "注册用户", "添加会议（格式：yyyy-MM-dd hh:mm:ss）"
            , "查询会议", "删除会议", "清除会议"
            , "查看帮助", "退出"
    };
    // 指令集参数
    private static final String[] INSTRUCTIONS_ARGS = {
            "[username] [password]"
            , "[username] [password] [otherusername] [start] [end] [title]"
            , "[username] [password] [start] [end]"
            , "[username] [password] [meetingid]"
            , "[username] [password]"
            , "no args", "no args"
    };

    protected MethodSetImpl() throws RemoteException {
    }

    /**
     * 获取用户集合
     * 
     * @return
     */
    private static synchronized Collection<User> getUsers() {
        return userHashtable.values();
    }

    /**
     * 获取会议集合
     * 
     * @return
     */
    private static synchronized Collection<Meeting> getMeetings() {
        return meetingHashtable.values();
    }
    
    /**
     * 注册
     *
     * @param username
     * @param password
     * @return  s：注册成功
     *          f：注册失败
     * @throws RemoteException
     */
    @Override
    public String register(String username, String password) throws RemoteException {
        // 如果用户名不存在
        if (!hasUsername(username)) {
            // 创建新用户
            User user = new User(username, password);
            // 添加用户到集合
            userHashtable.put(user.getId(), user);

            System.out.println(displayUsers());
            return "s";
        }
        return "f";
    }

    /**
     * 添加会议
     *
     * @param username
     * @param password
     * @param otherUsername
     * @param start
     * @param end
     * @param title
     * @return  success：    添加会议成功
     *          less：       当前注册用户不足两人
     *          same_name：  创建者和参会者相同
     *          wrong：      用户名或密码或参会者用户名错误
     *          wrong_date： 时间格式错误
     *          wrong_date_value：时间数值错误
     *          conflict：   会议时间冲突
     * @throws RemoteException
     */
    @Override
    public String add(String username, String password, String otherUsername, String start, String end, String title) throws RemoteException {
        // 1. 判断：用户名和密码是否正确
        // 1.1 判断当前是否存在两个及以上的user
        if (userHashtable.size() < 2) return "less";
        // 1.2 获取users集合
        users = getUsers();
        // 判断1标记
        boolean flag1 = false;
        // 2. 判断：参会者用户名是否正确
        // 2.1 判断参会者用户名和创建者用户名是否是同一个人
        if (username.equals(otherUsername)) return "same_name";
        // 判断2标记
        boolean flag2 = false;
        // 2.2 遍历users并判断条件
        for (User user : users) {
            if (user.getUsername().equals(username)
                    && user.getPassword().equals(password)) {
                flag1 = true;
                continue;
            }
            if (user.getUsername().equals(otherUsername)) {
                flag2 = true;
            }
            if (flag1 && flag2) break;
        }
        if (!(flag1 && flag2)) return "wrong";
        // 3. 判断：指定会议开始时间和结束时间是否合法
        // 3.1 判断：开始时间和结束时间格式是否合法
        // 将开始时间和结束时间包装成Date
        Date startDate;
        Date endDate;
        try {
            // SimpleDateFormat在yyyy-MM-dd hh:mm:ss最后如果存在非法字段会无视，所以自行判断
            if (start.split(" ")[1].length() != 8
                    || end.split(" ")[1].length() != 8) {
                throw new ParseException("", 0);
            }
            startDate = format.parse(start);
            System.out.println(end);
            endDate = format.parse(end);
        } catch (ParseException e) {
            return "wrong_date";
        }
        // 3.2 判断：开始时间是否小于等于结束时间
        if (startDate.after(endDate) || startDate.equals(endDate)) return "wrong_date_value";
        // 4. 判断：创建者和参会者是否时间冲突
        String creator;
        String participant;
        Date currentStart = null;
        Date currentEnd = null;

        meetings = getMeetings();
        // 4.1 判断当前是否有会议
        if (!meetings.isEmpty()) {
            // 4.2 遍历meetings并判断条件
            for (Meeting meeting : meetings) {
                creator = meeting.getUsername();
                participant = meeting.getOtherUsername();
                try {
                    currentStart = format.parse(meeting.getStart());
                    currentEnd = format.parse(meeting.getEnd());
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                // 判断时间冲突
                if ((username.equals(creator) || username.equals(participant))
                        || (otherUsername.equals(creator) || otherUsername.equals(participant))) {
                    if (timeConflict(startDate, endDate, currentStart, currentEnd)) return "conflict";
                }
            }
        }
        // 5. 创建会议
        Meeting meeting = new Meeting(username, otherUsername, start, end, title);
        meetingHashtable.put(meeting.getId(), meeting);

        System.out.println(displayMeetings());
        return "success";
    }

    /**
     * 查询会议
     *
     * @param username
     * @param password
     * @param start
     * @param end
     * @return  no_user：    未有注册用户
     *          wrong：      用户名或密码错误
     *          no_meeting： 未有添加会议
     *          wrong_date： 时间格式错误
     *          wrong_date_value：   时间数值错误
     *          ==Meetings== + xx：  查询成功
     *          none：       未查询到结果
     * @throws RemoteException
     */
    @Override
    public String query(String username, String password, String start, String end) throws RemoteException {
        // 1. 判断：用户名和密码是否正确
        // 1.1 判断是否存在用户
        if (userHashtable.isEmpty()) return "no_user";
        users = getUsers();
        // 判断1标志
        boolean flag1 = false;
        for (User user : users) {
            if (user.getUsername().equals(username)
                    && user.getPassword().equals(password)) {
                flag1 = true;
                break;
            }
        }
        if (!flag1) return "wrong";
        // 2. 判断：会议开始时间和结束时间是否合法
        if (meetingHashtable.isEmpty()) return "no_meeting";

        // 2.1 判断：会议时间格式是否合法
        Date startDate;
        Date endDate;
        try {
            if (start.split(" ")[1].length() != 8
                    || end.split(" ")[1].length() != 8) {
                throw new ParseException("", 0);
            }
            startDate = format.parse(start);
            endDate = format.parse(end);
        } catch (ParseException e) {
            return "wrong_date";
        }
        // 2.2 判断：会议时间数值是否合法
        if (startDate.after(endDate)) return "wrong_date_value";
        // 3. 查询时间区间内的会议
        Vector<Meeting> meetingVector = new Vector<>();
        meetings = getMeetings();

        String creator;
        String participant;
        Date currentStart = null;
        Date currentEnd = null;

        for (Meeting meeting : meetings) {
            creator = meeting.getUsername();
            participant = meeting.getOtherUsername();
            try {
                currentStart = format.parse(meeting.getStart());
                currentEnd = format.parse(meeting.getEnd());
            } catch (ParseException e) {
                e.printStackTrace();
            }
            // 存在时间区间内的会议
            if ((creator.equals(username)
                    || participant.equals(username))
                    && (currentStart.after(startDate)
                    && currentEnd.before(endDate))) {
                meetingVector.add(meeting);
            }
        }
        // 4. 如果查询到了会议，则按start时间排序
        if (!meetingVector.isEmpty()) {
            meetingVector.sort(Comparator.comparing(Meeting::getStart));
            String res = "==Meetings==\n";
            for (Meeting meeting : meetingVector) {
                res += meeting.toString() + "\n";
            }
            return res;
        }
        // 5. 未查询到会议
        return "none";
    }

    /**
     * 按 id删除会议
     *
     * @param username
     * @param password
     * @param meetingId
     * @return  no_user：    当前不存在用户
     *          wrong：      用户名或密码错误
     *          wrong_id：   会议 id错误
     *          no_meeting： 当前不存在会议
     *          none：       未查询到相关会议
     *          success：    删除成功
     * @throws RemoteException
     */
    @Override
    public String delete(String username, String password, String meetingId) throws RemoteException {
        // 1. 判断：用户名或密码是否正确
        // 1.1 判断：当前是否存在用户
        if(userHashtable.isEmpty()) return "no_user";
        users = getUsers();
        // 判断1标志
        boolean flag1 = false;
        for (User user : users) {
            if (user.getUsername().equals(username)
                    && user.getPassword().equals(password)) {
                flag1 = true;
                break;
            }
        }
        if (!flag1) return "wrong";
        // 2. 判断：是否存在该id的会议
        // 2.1 判断：id是否合法
        int id;
        try {
            id = Integer.parseInt(meetingId);
        } catch (NumberFormatException e) {
            return "wrong_id";
        }
        // 2.2 判断：是否有会议
        if (meetingHashtable.isEmpty()) return "no_meeting";
        // 2.3 遍历查询id
        meetings = getMeetings();

        // 判断2标志
        boolean flag2 = false;
        for (Meeting meeting : meetings) {
            if (meeting.getUsername().equals(username)
                    && id == meeting.getId()) {
                flag2 = true;
                meetingHashtable.remove(id);
                System.out.println(displayMeetings());
                break;
            }
        }
        if (!flag2) return "none";
        return "success";
    }

    /**
     * 删除会议
     *
     * @param username
     * @param password
     * @return  no_user：    当前不存在用户
     *          wrong：      用户名或密码错误
     *          no_meeting： 当前不存在会议
     *          none：       未查询到相关会议
     *          success：    删除会议成功
     * @throws RemoteException
     */
    @Override
    public String clear(String username, String password) throws RemoteException {
        // 1. 判断：用户名或密码是否正确
        // 1.1 判断：当前是否存在用户
        if(userHashtable.isEmpty()) return "no_user";
        users = getUsers();
        // 判断1标志
        boolean flag1 = false;
        for (User user : users) {
            if (user.getUsername().equals(username)
                    && user.getPassword().equals(password)) {
                flag1 = true;
                break;
            }
        }
        if (!flag1) return "wrong";
        // 2. 删除会议
        // 2.1 判断：当前是否存在会议
        if (meetingHashtable.isEmpty()) return "no_meeting";
        // 2.2 遍历删除
        meetings = getMeetings();
        Vector<Integer> meetingIds = new Vector<>();
        for (Meeting meeting : meetings) {
            if (username.equals(meeting.getUsername())) {
                meetingIds.add(meeting.getId());
            }
        }
        if (meetingIds.isEmpty()) return "none";
        for (Integer meetingId : meetingIds) {
            meetingHashtable.remove(meetingId);
        }
        System.out.println(displayMeetings());
        return "success";
    }

    /**
     * 输出指令菜单
     *
     * @return
     * @throws RemoteException
     */
    @Override
    public String help() throws RemoteException {
        String tab = "\t";
        String lf = "\n";
        String info = "RMI MENU:" + lf;
        for (int i = 0; i < 7; i++) {
            info += tab + (i + 1) + ". " + INSTRUCTIONS[i]
                    + tab + " : " + INSTRUCTIONS_DES[i] + lf;
            info += tab + tab + "arguments: " + INSTRUCTIONS_ARGS[i] + lf;
        }
        return info;
    }

    /**
     * 判断待创建会议和已存在会议是否时间冲突
     *
     * @param startDate
     * @param endDate
     * @param currentStart
     * @param currentEnd
     * @return  true：时间冲突
     *          false：时间不冲突
     */
    public boolean timeConflict(Date startDate, Date endDate, Date currentStart, Date currentEnd) {
        return !(endDate.before(currentStart) || startDate.after(currentEnd));
    }

    /**
     * 展示所有会议信息
     *
     * @return
     */
    public String displayMeetings() {
        String res = "";
        meetings = getMeetings();
        for (Meeting meeting : meetings) {
            res += meeting.toString() + "\n";
        }
        return res;
    }

    /**
     * 展示所有用户信息
     *
     * @return
     */
    public String displayUsers() {
        String res = "";
        users = getUsers();
        for (User user : users) {
            res += user.toString() + "\n";
        }
        return res;
    }

    /**
     * 判断 username是否已经存在
     *
     * @param username
     * @return  true：用户名已存在
     *          false：用户名不存在
     */
    public boolean hasUsername(String username) {
        users = getUsers();
        for (User user : users) {
            if (username.equals(user.getUsername())) {
                return true;
            }
        }
        return false;
    }
}
